{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 优化保存聊天信息\n",
    "\n",
    "使用字典保存聊天信息，更方便后面的信息的整理和显示"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def add_messages(username, message):\n",
    "    # 添加消息，保存在列表里面\n",
    "    now = datetime.now().strftime(\"%H:%M:%S\") # 记录时间：格式：00:00:00\n",
    "    messages_dict = {\"timestamp\": now, \"from\": username, \"message\": message} # 之前是字符串，现在换成字典保存\n",
    "    messages.append(messages_dict)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 制作聊天信息展示页面\n",
    "\n",
    "在`template`文件夹中`chat.html`文件，内容如下\n",
    "\n",
    "```\n",
    "<!DOCTYPE html>\n",
    "<html lang=\"zh-CN\">\n",
    "<head>\n",
    "    <meta charset=\"UTF-8\">\n",
    "    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n",
    "    <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n",
    "    <title>{{ username }}的聊天室</title>\n",
    "</head>\n",
    "<body>\n",
    "    <h1>欢迎, {{ username }}</h1>\n",
    "    {{ chat_messages }}\n",
    "    \n",
    "</body>\n",
    "</html>\n",
    "```\n",
    "\n",
    "这里`{{ username }}`和`{{ chat_messages }}`可以通过`render_template`函数传递参数，形式动态页面。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "@app.route(\"/<username>\")\n",
    "def user(username):\n",
    "    \"\"\"Display chat messages\"\"\"\n",
    "    return render_template(\"chat.html\", username=username,\n",
    "                           chat_messages=messages)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 完整代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " * Serving Flask app '__main__' (lazy loading)\n",
      " * Environment: production\n",
      "\u001b[31m   WARNING: This is a development server. Do not use it in a production deployment.\u001b[0m\n",
      "\u001b[2m   Use a production WSGI server instead.\u001b[0m\n",
      " * Debug mode: off\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      " * Running on all addresses.\n",
      "   WARNING: This is a development server. Do not use it in a production deployment.\n",
      " * Running on http://10.0.20.12:5000/ (Press CTRL+C to quit)\n",
      "113.70.248.211 - - [08/Jun/2022 15:28:46] \"GET / HTTP/1.1\" 200 -\n",
      "113.70.248.211 - - [08/Jun/2022 15:28:46] \"GET /favicon.ico HTTP/1.1\" 200 -\n",
      "113.70.248.211 - - [08/Jun/2022 15:28:49] \"POST / HTTP/1.1\" 302 -\n",
      "113.70.248.211 - - [08/Jun/2022 15:28:49] \"GET /louis HTTP/1.1\" 200 -\n",
      "113.70.248.211 - - [08/Jun/2022 15:28:50] \"GET /favicon.ico HTTP/1.1\" 200 -\n",
      "113.70.248.211 - - [08/Jun/2022 15:30:09] \"GET /louis/hello HTTP/1.1\" 302 -\n",
      "113.70.248.211 - - [08/Jun/2022 15:30:09] \"GET /louis HTTP/1.1\" 200 -\n",
      "113.70.248.211 - - [08/Jun/2022 15:30:09] \"GET /favicon.ico HTTP/1.1\" 200 -\n"
     ]
    }
   ],
   "source": [
    "from datetime import datetime\n",
    "from flask import Flask, redirect, render_template, request, session\n",
    "\n",
    "\n",
    "app = Flask(__name__)\n",
    "app.secret_key = \"randomstring12345\"  # 大家可以不一样的，用于生成随机ID的随机种子，类似random的seed\n",
    "messages = []\n",
    "\n",
    "\n",
    "def add_messages(username, message):\n",
    "    # 添加消息，保存在列表里面\n",
    "    now = datetime.now().strftime(\"%H:%M:%S\") # 记录时间：格式：00:00:00\n",
    "    messages_dict = {\"timestamp\": now, \"from\": username, \"message\": message} # 之前是字符串，现在换成字典保存\n",
    "    messages.append(messages_dict)\n",
    "\n",
    "def get_all_messages():\n",
    "    \"\"\"获取关于我的所有聊天信息`\"\"\"\n",
    "    return \"<br>\".join(messages)\n",
    "\n",
    "\n",
    "\n",
    "@app.route(\"/\", methods=[\"GET\", \"POST\"])  # 允许的方法有POST和GET，其他不写methods默认就是GET\n",
    "def index():\n",
    "    \"\"\"主页\"\"\"\n",
    "    if request.method == \"POST\":\n",
    "        # 如果是POST请求，进入这里，在请求中把username放到session里面\n",
    "        session[\"username\"] = request.form[\"username\"]\n",
    "\n",
    "    if \"username\" in session:\n",
    "        # 如果session中有username这个键值，就转跳到对应的用户页面\n",
    "        return redirect(session[\"username\"])\n",
    "    \n",
    "    # 如果没有，就展示首页网页。\n",
    "    return render_template(\"index2.html\")\n",
    "\n",
    "# @app.route(\"/tiger\")\n",
    "# def hu():\n",
    "#     return render_template(\"tiger.html\")\n",
    "\n",
    "@app.route(\"/<username>\")\n",
    "def user(username):\n",
    "    \"\"\"Display chat messages\"\"\"\n",
    "    return render_template(\"chat.html\", username=username,\n",
    "                           chat_messages=messages)\n",
    "\n",
    "\n",
    "@app.route(\"/<username>/<message>\")\n",
    "def send_message(username, message):\n",
    "    \"\"\"\n",
    "    通过路由设置:/人名称/信息内容 来实现发送信息给某人\n",
    "    添加信息到列表里面，然后返回到用户页面\n",
    "    \"\"\"\n",
    "    add_messages(username, message)\n",
    "    return redirect(\"/\" + username)\n",
    "\n",
    "app.run(host=\"0.0.0.0\") # 启动服务器"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 优化信息显示\n",
    "\n",
    "上面的聊天信息显示是直接把字典打印出来，如下\n",
    "```\n",
    "[{'timestamp': '23:48:35', 'from': '李娜', 'message': '大家好'}] \n",
    "```\n",
    "可以说很丑，我们需要通过html优化。 当我们打开聊天页面，其他人再发新消息来的时候，我们的页面是没有马上更新内容的，需要手动刷新页面才能接受新的消息，因此我们也要增加一个自动刷新功能。 因此新的chat2.html改进如下：\n",
    "\n",
    "```\n",
    "<!DOCTYPE html>\n",
    "<html lang=\"zh-CN\">\n",
    "<head>\n",
    "    <meta charset=\"UTF-8\">\n",
    "    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n",
    "    <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n",
    "    <title>{{ username }}的聊天室</title>\n",
    "</head>\n",
    "<body>\n",
    "    <h1>欢迎, {{ username }}</h1>\n",
    "    \n",
    "    {% for message in chat_messages %}\n",
    "        <p>({{ message.timestamp }}) {{ message.from }}: {{ message.message }}</p>\n",
    "    {% endfor %}\n",
    "    \n",
    "    <script>\n",
    "        let timer=setTimeout(function() {\n",
    "            location.reload()\n",
    "        }, 5000)\n",
    "    </script>\n",
    "    \n",
    "</body>\n",
    "</html>\n",
    "```\n",
    "\n",
    "## 修改代码\n",
    "\n",
    "把返回的文件改成新的chat2.html，然后查看效果。\n",
    "\n",
    "```\n",
    "@app.route(\"/<username>\")\n",
    "def user(username):\n",
    "    \"\"\"Display chat messages\"\"\"\n",
    "    return render_template(\"chat2.html\", username=username,\n",
    "                           chat_messages=messages)\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from datetime import datetime\n",
    "from flask import Flask, redirect, render_template, request, session\n",
    "\n",
    "\n",
    "app = Flask(__name__)\n",
    "app.secret_key = \"randomstring12345\"  # 大家可以不一样的，用于生成随机ID的随机种子，类似random的seed\n",
    "messages = []\n",
    "\n",
    "\n",
    "def add_messages(username, message):\n",
    "    # 添加消息，保存在列表里面\n",
    "    now = datetime.now().strftime(\"%H:%M:%S\") # 记录时间：格式：00:00:00\n",
    "    messages_dict = {\"timestamp\": now, \"from\": username, \"message\": message} # 之前是字符串，现在换成字典保存\n",
    "    messages.append(messages_dict)\n",
    "\n",
    "def get_all_messages():\n",
    "    \"\"\"获取关于我的所有聊天信息`\"\"\"\n",
    "    return \"<br>\".join(messages)\n",
    "\n",
    "\n",
    "\n",
    "@app.route(\"/\", methods=[\"GET\", \"POST\"])  # 允许的方法有POST和GET，其他不写methods默认就是GET\n",
    "def index():\n",
    "    \"\"\"主页\"\"\"\n",
    "    if request.method == \"POST\":\n",
    "        # 如果是POST请求，进入这里，在请求中把username放到session里面\n",
    "        session[\"username\"] = request.form[\"username\"]\n",
    "\n",
    "    if \"username\" in session:\n",
    "        # 如果session中有username这个键值，就转跳到对应的用户页面\n",
    "        return redirect(session[\"username\"])\n",
    "    \n",
    "    # 如果没有，就展示首页网页。\n",
    "    return render_template(\"index2.html\")\n",
    "\n",
    "\n",
    "@app.route(\"/<username>\")\n",
    "def user(username):\n",
    "    \"\"\"Display chat messages\"\"\"\n",
    "    return render_template(\"chat2.html\", username=username,\n",
    "                           chat_messages=messages)\n",
    "\n",
    "\n",
    "@app.route(\"/<username>/<message>\")\n",
    "def send_message(username, message):\n",
    "    \"\"\"\n",
    "    通过路由设置:/人名称/信息内容 来实现发送信息给某人\n",
    "    添加信息到列表里面，然后返回到用户页面\n",
    "    \"\"\"\n",
    "    add_messages(username, message)\n",
    "    return redirect(\"/\" + username)\n",
    "\n",
    "app.run() # 启动服务器"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "                           \n",
    "### 输入信息非常困难\n",
    "\n",
    "我们需要优化信息输入，因此要做一个信息输入框，用于提交新的聊天内容。具体内容如chat3.html:\n",
    "\n",
    "```\n",
    "<!DOCTYPE html>\n",
    "<html lang=\"zh-CN\">\n",
    "<head>\n",
    "    <meta charset=\"UTF-8\">\n",
    "    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n",
    "    <meta http-equiv=\"X-UA-Compatible\" content=\"ie=edge\">\n",
    "    <title>{{ username }}的聊天室</title>\n",
    "</head>\n",
    "<body>\n",
    "    <h1>欢迎， {{ username }}</h1>\n",
    "    \n",
    "    <form method = \"POST\">\n",
    "        <textarea cols=\"50\" rows=\"4\" name=\"message\" id=\"message\"></textarea>\n",
    "        <br>\n",
    "        <button>发送</button>\n",
    "    </form>\n",
    "    \n",
    "    {% for message in chat_messages %}\n",
    "        <p>({{ message.timestamp }}) {{ message.from }}: {{ message.message }}</p>\n",
    "    {% endfor %}\n",
    "    \n",
    "    <script>\n",
    "        let textbox = document.getElementById(\"message\")\n",
    "    \n",
    "        let timer = setTimeout(function() {\n",
    "            location.reload();\n",
    "        }, 5000)\n",
    "        \n",
    "        textbox.onkeydown = function(e) {\n",
    "            \n",
    "            clearTimeout(timer)\n",
    "            \n",
    "            timer = setTimeout(function() {\n",
    "                location.reload();\n",
    "            }, 5000)\n",
    "            \n",
    "        }\n",
    "        \n",
    "    </script>\n",
    "    \n",
    "</body>\n",
    "</html>\n",
    "\n",
    "```\n",
    "\n",
    "然后对应的路由功能也要增加POST方法。\n",
    "```\n",
    "@app.route(\"/<username>\", methods=[\"GET\", \"POST\"])\n",
    "def user(username):\n",
    "    \"\"\"Display chat messages\"\"\"\n",
    "    if request.method == \"POST\":\n",
    "        username = session[\"username\"]\n",
    "        message = request.form[\"message\"]\n",
    "        add_messages(username, message)\n",
    "        return redirect(session[\"username\"])\n",
    "\n",
    "    return render_template(\"chat3.html\", username=username,\n",
    "                           chat_messages=messages)\n",
    "```\n",
    "\n",
    "## 优化后的代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from datetime import datetime\n",
    "from flask import Flask, redirect, render_template, request, session\n",
    "\n",
    "\n",
    "app = Flask(__name__)\n",
    "app.secret_key = \"randomstring12345\"  # 大家可以不一样的，用于生成随机ID的随机种子，类似random的seed\n",
    "messages = []\n",
    "\n",
    "\n",
    "def add_messages(username, message):\n",
    "    # 添加消息，保存在列表里面\n",
    "    now = datetime.now().strftime(\"%H:%M:%S\") # 记录时间：格式：00:00:00\n",
    "    messages_dict = {\"timestamp\": now, \"from\": username, \"message\": message} # 之前是字符串，现在换成字典保存\n",
    "    messages.append(messages_dict)\n",
    "\n",
    "def get_all_messages():\n",
    "    \"\"\"获取关于我的所有聊天信息`\"\"\"\n",
    "    return \"<br>\".join(messages)\n",
    "\n",
    "\n",
    "\n",
    "@app.route(\"/\", methods=[\"GET\", \"POST\"])  # 允许的方法有POST和GET，其他不写methods默认就是GET\n",
    "def index():\n",
    "    \"\"\"主页\"\"\"\n",
    "    if request.method == \"POST\":\n",
    "        # 如果是POST请求，进入这里，在请求中把username放到session里面\n",
    "        session[\"username\"] = request.form[\"username\"]\n",
    "\n",
    "    if \"username\" in session:\n",
    "        # 如果session中有username这个键值，就转跳到对应的用户页面\n",
    "        return redirect(session[\"username\"])\n",
    "    \n",
    "    # 如果没有，就展示首页网页。\n",
    "    return render_template(\"index2.html\")\n",
    "\n",
    "\n",
    "@app.route(\"/<username>\", methods=[\"GET\", \"POST\"])\n",
    "def user(username):\n",
    "    \"\"\"个人聊天室\"\"\"\n",
    "    if request.method == \"POST\":\n",
    "        # 如果是提交聊天内容，则在这里处理\n",
    "        username = session[\"username\"]\n",
    "        message = request.form[\"message\"]\n",
    "        add_messages(username, message)\n",
    "        return redirect(session[\"username\"])\n",
    "    \n",
    "    # 若不是，则显示所有聊天内容\n",
    "    return render_template(\"chat3.html\", username=username,\n",
    "                           chat_messages=messages)\n",
    "\n",
    "@app.route(\"/<username>/<message>\")\n",
    "def send_message(username, message):\n",
    "    \"\"\"\n",
    "    通过路由设置:/人名称/信息内容 来实现发送信息给某人\n",
    "    添加信息到列表里面，然后返回到用户页面\n",
    "    \"\"\"\n",
    "    add_messages(username, message)\n",
    "    return redirect(\"/\" + username)\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    app.run(host=\"0.0.0.0\", port=5001)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
